/**
 *  Copyright 2002-2009 the original author or authors.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package foo.bar.forum.security;

import org.jsecurity.authz.Permission;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;

import java.util.List;
import java.util.Set;

/**
 * An extension of {@link foo.bar.forum.security.ExtendedWildcardPermission} that provides hooks
 * (abstract methods) that allowed an {@link foo.bar.forum.security.ExtendedWildcardPermission} to
 * be "translated" before "implication" ({@link #implies(org.jsecurity.authz.Permission)})
 * is done between the 2 {@link foo.bar.forum.security.ExtendedWildcardPermission}
 *
 * @See {@link #translate(foo.bar.forum.security.ExtendedWildcardPermission)}
 * @See {@link #canTranslate(ExtendedWildcardPermission)} 
 *
 * @author tmjee
 * @version $Date: 2009-03-16 21:46:02 +0800 (Mon, 16 Mar 2009) $ $Id$
 */
public abstract class AbstractExtendedWildcardPermission extends ExtendedWildcardPermission {

    private static final Log LOG = LogFactory.getLog(AbstractExtendedWildcardPermission.class);

    public AbstractExtendedWildcardPermission(String wildcardString) {
        super(wildcardString);
    }

    public AbstractExtendedWildcardPermission(String wildcardString, boolean caseSensitive) {
        super(wildcardString, caseSensitive);
    }


    public boolean implies(Permission p) {
        ExtendedWildcardPermission effectivePermission1 = (ExtendedWildcardPermission) p;
        ExtendedWildcardPermission effectivePermission2 = this;

        if (p instanceof ExtendedWildcardPermission2) {
            ExtendedWildcardPermission2 permission = (ExtendedWildcardPermission2) p;
            if (canTranslate(permission)) {
                ExtendedWildcardPermission _translatedPermission = translate(permission);
                effectivePermission1 = _translatedPermission;
            }
        }

        if (this instanceof ExtendedWildcardPermission2) {
            ExtendedWildcardPermission2 permission = (ExtendedWildcardPermission2) this;
            if (canTranslate(permission)) {
                ExtendedWildcardPermission _translatedPermission = translate(permission);
                effectivePermission2 = _translatedPermission;
            }
        }
        boolean result =  _implies(effectivePermission2, effectivePermission1);
                return result;
    }

    protected abstract boolean canTranslate(ExtendedWildcardPermission p);
    protected abstract ExtendedWildcardPermission translate(ExtendedWildcardPermission p);


    /**
     * Work out implecation between p1 and p2, where p1 is this permission and p2 is the other permission.
     *
     * @param p1
     * @param p2
     * @return
     */
    private boolean _implies(ExtendedWildcardPermission p1, ExtendedWildcardPermission p2) {

        List<Set<String>> otherParts = p2.getParts();

        int i = 0;
        for (Set<String> otherPart : otherParts) {

            // If this permission has less parts than the other permission, everything after the number of parts contained
            // in this permission is automatically implied, so return true
            if (p1.getParts().size() - 1 < i) {
                return true;

            } else {
                Set<String> part = p1.getParts().get(i);

                if (!part.contains(WILDCARD_TOKEN) && !part.containsAll(otherPart)) {
                    return false;
                }

                i++;
            }

        }

        // If this permission has more parts than the other parts, only imply it if all of the other parts are wildcards
        for (; i < p1.getParts().size(); i++) {
            Set<String> part = p1.getParts().get(i);
            if (!part.contains(WILDCARD_TOKEN)) {
                return false;
            }
        }

        return true;
    }
}
